package com.mimo.comet.provider.command;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.util.StringUtils;

import com.fasterxml.jackson.annotation.JsonIgnore;
import com.fasterxml.jackson.annotation.JsonTypeInfo;
import com.fasterxml.jackson.annotation.JsonTypeInfo.As;
import com.fasterxml.jackson.annotation.JsonTypeInfo.Id;
import com.fasterxml.jackson.databind.DatabindContext;
import com.fasterxml.jackson.databind.JavaType;
import com.fasterxml.jackson.databind.annotation.JsonTypeIdResolver;
import com.fasterxml.jackson.databind.jsontype.impl.TypeIdResolverBase;
import com.mimo.comet.provider.command.BaseCommand.CommandTypeIdResolver;
import com.mimo.common.utils.JsonUtils;

import io.swagger.annotations.ApiModelProperty;

@JsonTypeInfo(use = Id.CUSTOM, include = As.EXISTING_PROPERTY, property = "type", visible = true)
@JsonTypeIdResolver(CommandTypeIdResolver.class)
public abstract class BaseCommand {
    private static final Logger log = LoggerFactory.getLogger(BaseCommand.class);

    /**
     * 每一个消息ID的长度必须是32位的UUID
     */
    protected static final int FIX_ID_SIZE = 32;

    /**
     * 指令ID,由发送端进行维护,需要保证该字段的唯一性
     * <p>
     * 业务上需要保证 用户+id的唯一性，以避免重复传递
     */
    @ApiModelProperty(value = "指令ID,由发送端进行维护,需要保证该字段的唯一性", required = true)
    protected String id;

    /**
     * 指令类型
     */
    @ApiModelProperty(value = "指令类型", required = true)
    protected CommandType type;

    /**
     * 指令收到时的时间点
     */
    @ApiModelProperty(value = "收到指令的时间点,请求端可以不填写", required = true, hidden = true)
    protected long timestamp;

    protected BaseCommand() {
        super();
        this.timestamp = System.currentTimeMillis();
    }

    /**
     * 由各自子类验证自身消息的完整性
     * <p>
     * 一般情况下，这是不可能发生的，但是考虑到非法用户入侵的可能性,还是需要校验的
     * 
     * @throw IllegalArgumentException 若参数非法,则抛出异常
     */
    @JsonIgnore
    public boolean isValid() {
        if (StringUtils.isEmpty(id) || id.length() != FIX_ID_SIZE) {
            log.error("CMD ID[{}]长度非法", id);
            return false;
        }
        return true;
    }

    public String getId() {
        return id;
    }

    public void setId(String id) {
        this.id = id;
    }

    public CommandType getType() {
        return type;
    }

    public long getTimestamp() {
        return timestamp;
    }

    @Override
    public String toString() {
        return JsonUtils.toJsonString(this);
    }

    /**
     * 自定义一个组件解析器，以便于存储和解析 JSON的动态反序列化
     * 
     * @author Hongyu
     */
    public static class CommandTypeIdResolver extends TypeIdResolverBase {

        @Override
        public String idFromValue(Object value) {
            return BaseCommand.class.cast(value).getType().name();
        }

        @Override
        public String idFromValueAndType(Object value, Class<?> suggestedType) {
            return BaseCommand.class.cast(value).getType().name();
        }

        @Override
        public Id getMechanism() {
            throw new UnsupportedOperationException();
        }

        @Override
        public JavaType typeFromId(DatabindContext context, String id) {
            return context.constructType(CommandType.valueOf(id).getCmdClz());
        }
    }

}
